#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import shutil
import time
import datetime
import logging
import asyncio
import re


# любитель філе, а не файл людина
class Fileman:
    def __init__(self, watch_target_subpath):
        """
        watch_target_subpath = {
            "watch": "path/to/watch",
            "target": "path/to/target",
            "subpaths":[
                {"name": ["ext1", "ext2"]},
                {"name2": ["ext3", "ext4"]}
            ]
        }
        """
        time.sleep(0.3)
        self.id = time.time_ns()
        print(f"Fileman ID: {self.id}")

        self.watch = watch_target_subpath['watch']
        self.target = watch_target_subpath['target']
        self.subpaths = watch_target_subpath['subpaths']
        self.check_dirs()

    def check_dirs(self):
        assert os.path.exists(self.watch), f"Папки `{self.watch}` не існує"
        if not os.path.exists(self.target):
            os.makedirs(self.target)
        for subpath in self.subpaths:
            subpath = list(subpath.keys())[0]
            subpath = self.path_plus_path(self.target, subpath)
            if not os.path.exists(subpath):
                os.makedirs(subpath)
        return True

    def path_plus_path(self, path_1, path_2):
        return f"{path_1}/{path_2}".replace('\\', '/')

    def target_by_file(self, files):
        files_to_move = {}
        iterations = 0
        for subpath in self.subpaths:
            key = list(subpath.keys())[0]
            exts = subpath[key]
            files_to_move[key] = []
            iterations += 1
            for ext in exts:
                iterations += 1
                for file in files:
                    iterations += 1
                    if file.lower().endswith(f".{ext}"):
                        files_to_move[key].append(file)
        logging.info(f"target_by_file ітерації: {iterations}")
        return files_to_move

    def rename_file(self, target, file):
        path_to = self.path_plus_path(target, file)
        if not os.path.exists(path_to):
            return path_to
        else:
            match = re.match(r'^\[(\d{1,})\]', file)
            if match:
                num = int(match.group(1)) + 1
                file = re.sub(r'^\[(\d{1,})\]', f'[{num}]', file)
            else:
                file = f"[0] {file}"
            return self.rename_file(target, file)

    def move_files(self, files):
        keys = list(files.keys())
        for key in keys:
            target = self.path_plus_path(self.target, key)
            for file in files[key]:
                try:
                    path_from = self.path_plus_path(self.watch, file)
                    path_to = self.rename_file(target, file)
                    shutil.move(path_from, path_to)
                except PermissionError:
                    logging.info(f"Або нема дозволу або файл {file} відкрито в іншій програмі")
                    logging.info("    В наступній перевірці файлів спробу перемістити буде повторено")

    def check_files(self):
        files = os.listdir(self.watch)
        target_files = self.target_by_file(files)
        self.move_files(target_files)

    def work(self, pause):
        """ pause - пауза між перевірками в секундах """
        while True:
            self.check_files()
            time.sleep(pause)
            print(f"\r [{datetime.datetime.now()}] [{self.id}] Працюю, прикинь", end="")
            logging.info(f"Працюю, прикинь [{self.id}]")

    async def async_work(self, pause):
        while True:
            self.check_files()
            await asyncio.sleep(pause)
            print(f"\r [{datetime.datetime.now()}] [{self.id}] Працюю, прикинь", end="")
            logging.info(f"Працюю, прикинь [{self.id}]")